﻿/*--------------------------------------------------------------
 * Author : Shine K Velayudhan 
 ---------------------------------------------------------------*/
using System;
using System.Collections.Generic;

namespace IQN.Logging
{
    internal sealed class Logger : ILogger
    {
        private MessageLevel? assignedThreshold = null;
        private List<Logger> children = null;
        private MessageLevel? effectiveThreshold = null;
        private readonly LoggerRepository loggerTree = null;
        private readonly string name = null;
        private Logger parent = null;
        private readonly MessageLevel DefaultThreshold = MessageLevel.Info;

        internal Logger(LoggerRepository loggerTree, string loggerName)
        {
            if (null == loggerTree)
            {
                throw new ArgumentNullException("loggerTree");
            }
            if (string.IsNullOrEmpty(loggerName))
            {
                throw new ArgumentException("loggerName required.");
            }
            this.loggerTree = loggerTree;
            this.name = loggerName;
        }

        private void ClearEffectiveThreshold()
        {
            this.effectiveThreshold = null;
        }

        internal void ClearThreshold()
        {
            this.assignedThreshold = null;
            this.VisitDescendents(delegate(Logger logger)
            {
                logger.ClearEffectiveThreshold();
            }, true);
        }

        private void ComputeEffectiveThreshold()
        {
            if (this.assignedThreshold.HasValue)
            {
                this.effectiveThreshold = this.assignedThreshold;
            }
            else if (null != this.Parent)
            {
                this.effectiveThreshold = this.Parent.Threshold;
            }
            else
            {
                this.effectiveThreshold = this.DefaultThreshold;
            }
        }

        void ILogger.Log(Exception error)
        {
            try
            {
                if (null != error)
                {
                    ErrorMessage errorMessage = new ErrorMessage(this.LoggerName, MessageLevel.Critical, error);
                    this.LoggerTree.ErrorLogCache.QueueMessage(errorMessage, true);
                    TraceMessage traceMessage = new TraceMessage(this.LoggerName, MessageLevel.Critical, errorMessage.RootCause, null, null);
                    this.LoggerTree.TraceLogCache.QueueMessage(traceMessage, true);
                }
            }
            catch { }
        }

        void ILogger.Log(MessageLevel severity, string message, object param1, object param2)
        {
            try
            {
                if (((null != message) && (severity >= this.Threshold)) && !this.LoggerTree.TraceLogCache.IsFull)
                {
                    TraceMessage traceMessage = new TraceMessage(this.LoggerName, severity, message, param1, param2);
                    this.LoggerTree.TraceLogCache.QueueMessage(traceMessage, false);
                }
            }
            catch { }
        }

        void ILogger.Log(MessageLevel severity, string eventTag, string component, DateTime startTime, DateTime endTime, string tag1, string tag2)
        {
            try
            {
                if (((null != eventTag) && (null != component)) && ((severity >= this.Threshold) && !this.LoggerTree.PerformanceLogCache.IsFull))
                {
                    long num = Math.Min(startTime.Ticks, endTime.Ticks);
                    long durationInTicks = Math.Max(startTime.Ticks, endTime.Ticks) - num;
                    PerformanceMessage message = new PerformanceMessage(this.LoggerName, severity, eventTag, component, durationInTicks, tag1, tag2);
                    this.LoggerTree.PerformanceLogCache.QueueMessage(message, false);
                }
            }
            catch { }
        }

        internal IList<Logger> EnsureChildren()
        {
            if (null == this.children)
            {
                this.children = new List<Logger>();
            }
            return this.children;
        }

        internal void VisitDescendents(Action<Logger> action, bool includeMe)
        {
            if (includeMe)
            {
                action(this);
            }
            if ((this.children != null) && (this.children.Count > 0))
            {
                Logger[] loggerArray = this.children.ToArray();
                foreach (Logger logger in loggerArray)
                {
                    logger.VisitDescendents(action, true);
                }
            }
        }

        internal void VisitParents(Action<Logger> action, bool includeMe)
        {
            if (includeMe)
            {
                action(this);
            }
            for (Logger logger = this.Parent; null != logger; logger = logger.Parent)
            {
                action(logger);
            }
        }

        internal IList<Logger> Children
        {
            get
            {
                if (null == this.children)
                {
                    throw new InvalidOperationException("Logger has no children. Check HasChildren first!");
                }
                return this.children;
            }
        }

        string ILogger.Name
        {
            get
            {
                return this.LoggerName;
            }
        }

        internal bool HasChildren
        {
            get
            {
                return ((this.children != null) && (this.children.Count > 0));
            }
        }

        internal string LoggerName
        {
            get
            {
                return this.name;
            }
        }

        internal LoggerRepository LoggerTree
        {
            get
            {
                return this.loggerTree;
            }
        }

        internal Logger Parent
        {
            get
            {
                return this.parent;
            }
            set
            {
                if (null == value)
                {
                    throw new InvalidOperationException("Can't assign null to Logger.Parent");
                }
                this.parent = value;
            }
        }

        internal MessageLevel Threshold
        {
            get
            {
                if (!this.effectiveThreshold.HasValue)
                {
                    this.ComputeEffectiveThreshold();
                }
                return this.effectiveThreshold.Value;
            }
            set
            {
                this.assignedThreshold = value;
                this.VisitDescendents(delegate(Logger logger)
                {
                    logger.ClearEffectiveThreshold();
                }, true);
            }
        }
    }
}
